#ifndef VL_SOCKETSTREAM_HPP
#define VL_SOCKETSTREAM_HPP

#include "stream.hpp"
#include "sockets.hpp"
#include "flags.hpp"

namespace vl
{

struct socket_buf : public device_buf, protected flags
{
	socket_buf(socket sock);

	socket_buf(char const* addr, int port);
	
	bool wait_for_data(int microsec);
	
	virtual size_t read(byte* p, size_t size);
	
	virtual size_t write(byte const* p, size_t size);
	
	virtual int error()
	{
		return all_flags(error_occured);
	}
	
	void set_no_delay(int opt = 1)
	{
		vl::set_no_delay(sock, opt);
	}
	
	void process();
	
	void do_close();
	
	~socket_buf();

private:
	
	enum socket_flags
	{
		connected = (1 << 0),
		connecting = (1 << 1),
		error_occured = (1 << 2)
	};
	
	socket sock;
	
};

#if 0 // TODO
struct udpstream_socket_buf : public device_buf, protected flags
{
	udpstream_socket_buf(socket sock);

	udpstream_socket_buf(char const* addr, int port);
	
	bool wait_for_data(int microsec);
	
	virtual size_t read(byte* p, size_t size);
	
	virtual size_t write(byte const* p, size_t size);
	
	bool would
	
	virtual int error()
	{
		return all_flags(error_occured);
	}
	
	void process();
	
	void do_close();
	
	~socket_buf();

private:
	
	enum socket_flags
	{
		connected = (1 << 0),
		connecting = (1 << 1),
		error_occured = (1 << 2)
	};
	
	socket sock;
	
};
#endif

struct socket_listener
{
	socket_listener();
	
	socket_listener(int port);
	
	~socket_listener();
	
	bool listen(int port);
	
	socket_buf* accept();
	
	void set_blocking(void (*blocking)(socket_listener*))
	{
		this->blocking = blocking;
	}
	
#if defined(ENABLE_PCL)
	static void coro_blocking(socket_listener*)
	{
		pcl::resume();
	}
	
	void set_coro_blocking()
	{
		set_blocking(coro_blocking);
	}
#endif
	
	void close();
	
	socket sock;
	void (*blocking)(socket_listener*);
};

struct socketstream : stream
{
	socketstream(char const* addr, int port);
	
	socketstream(socket_buf* buf)
	: iobase(buf)
	{
	}
	
	bool wait_for_data(int microsec)
	{
		return static_cast<socket_buf*>(dev)->wait_for_data(microsec);
	}
};

} // namespace vl

#endif // VL_SOCKETSTREAM_HPP
